package com.demo.camunda.controller;

import com.demo.camunda.camundaBO.ProcessDefinitionBO;
import com.demo.camunda.service.TempService;
import com.demo.camunda.util.CommonResult;
import org.apache.commons.io.FileUtils;
import org.camunda.bpm.engine.*;
import org.camunda.bpm.engine.impl.pvm.process.ProcessDefinitionImpl;
import org.camunda.bpm.engine.impl.util.IoUtil;
import org.camunda.bpm.engine.management.ActivityStatistics;
import org.camunda.bpm.engine.repository.Deployment;
import org.camunda.bpm.engine.repository.ProcessDefinition;
import org.camunda.bpm.engine.repository.ProcessDefinitionQuery;
import org.camunda.bpm.engine.rest.dto.repository.ProcessDefinitionDiagramDto;
import org.camunda.bpm.engine.rest.exception.InvalidRequestException;
import org.camunda.bpm.engine.rest.exception.RestException;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.ws.rs.core.Response;
import java.io.*;
import java.util.*;

@RestController
public class TempController {
    private static Logger logger = LoggerFactory.getLogger(TempController.class);

    @Resource
    private RepositoryService repositoryService;
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private ManagementService managementService;
    @Resource
    private TaskService taskService;

    @Resource
    private  ProcessEngine processEngine;


    @Autowired
    TempService tempService;


    @GetMapping("/temp")
    public String tempController() {
        return "temp";
    }

    @PostMapping("/list")
    public List<Map<String, Object>> listUser() {
        return tempService.listUser();
    }


    // todo 部署流程到引擎上,此方法为案例方法，后续需要改动
    @PostMapping("/deploy")
    public CommonResult deploy() throws IOException {
        String path = "D:\\diagram.BPMN";
        FileInputStream fileInputStream = new FileInputStream(path);
        Deployment deploy = repositoryService.createDeployment()
                .addInputStream("测试流程.bpmn", fileInputStream)
                .name("测试流程1")
                .deploy();
        fileInputStream.close();
        logger.info(deploy.getName());
        logger.info(deploy.getId());

        return CommonResult.success();
    }


    /**
     * @param processDefinitionKey
     * @return List<ProcessDefinitionBO>
     * 查询流程的所有版本的流程
     * processDefinitionKey  Process_1656572076848
     */
    @ResponseBody
    @PostMapping("/getProcessDefinitionById")
    public List<ProcessDefinitionBO> getProcessDefinitionById(String processDefinitionKey) {

        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        List<ProcessDefinition> processDefs = processDefinitionQuery
                .processDefinitionKey(processDefinitionKey)
                .orderByProcessDefinitionVersion()
                .desc()
                .list();
        List<ProcessDefinitionImpl> ll = new ArrayList<>();
        for (ProcessDefinition pd : processDefs) {
            logger.info(pd.getId() + " , " + pd.getName() + " , "
                    + pd.getKey() + " , " + pd.getVersion());
            ProcessDefinitionImpl pdObj = (ProcessDefinitionImpl) repositoryService.getProcessDefinition(pd.getId());
            pdObj.setParticipantProcess(null);
            ll.add(pdObj);
        }
        List<ProcessDefinitionBO> t = new ArrayList<>();
        ll.stream().forEach(o -> {
            ProcessDefinitionBO processDefinitionBO = new ProcessDefinitionBO();
            processDefinitionBO.setId(o.getId());
            processDefinitionBO.setDeploymentId(o.getDeploymentId());
            processDefinitionBO.setDiagramResourceName(o.getDiagramResourceName());
            t.add(processDefinitionBO);

        });

        return t;

    }


    /**
     * 开始一个流程实例
     * 如果有多个版本的流程，传入流程id，默认启动最新一版的流程
     */
    @PostMapping("/startByInstanceId")
    public String startByInstanceId(String proInsId) {
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(proInsId);
        String id = processInstance.getId();
        return id;

    }

    /**
     * 查询单个流程定义
     * <p>
     * processDefinitionId 是act_re_procdef 的id值:Process_1656572076848:1:2378c583-f842-11ec-908a-f4a4757e3c26
     */
    @PostMapping("/getProcessDefinitionByIdOne")
    public ProcessDefinitionBO getProcessDefinitionByIdOne(String processDefinitionId) {
        ProcessDefinition o = repositoryService.getProcessDefinition(processDefinitionId);
        ProcessDefinitionBO processDefinitionBO = new ProcessDefinitionBO();
        processDefinitionBO.setId(o.getId());
        processDefinitionBO.setDeploymentId(o.getDeploymentId());
        processDefinitionBO.setDiagramResourceName(o.getDiagramResourceName());
        return processDefinitionBO;
    }

    /**
     * 获取流程定义的文件资源-XML
     *
     * @param processDefinitionId
     * @return
     * @throws UnsupportedEncodingException
     */
    @PostMapping("/getProcessModel")
    public CommonResult<Map> getProcessModel(String processDefinitionId)   {
//        BpmnModelInstance bpmnModelInstance = repositoryService.getBpmnModelInstance(processDefinitionId);
        InputStream processModelIn = null;
        try {
            processModelIn = repositoryService.getProcessModel(processDefinitionId);
            byte[] processModel = IoUtil.readInputStream(processModelIn, "processModelBpmn20Xml");
            ProcessDefinitionDiagramDto processDefinitionDiagramDto = ProcessDefinitionDiagramDto
                    .create(processDefinitionId, new String(processModel, "UTF-8"));
            System.out.println(processDefinitionDiagramDto);
            Map<String, Object> data = new HashMap<String, Object>();
            data.put("bpmn20Xml", processDefinitionDiagramDto);
            data.put("id", processDefinitionId);
            return CommonResult.success(data);
        } catch (AuthorizationException e) {
            throw e;
        } catch (ProcessEngineException e) {
            throw new InvalidRequestException(Response.Status.BAD_REQUEST,
                    e, "No matching definition with id " + processDefinitionId);
        } catch (UnsupportedEncodingException e) {
            throw new RestException(Response.Status.INTERNAL_SERVER_ERROR, e);
        } finally {
            IoUtil.closeSilently(processModelIn);
        }
    }


    /**
     * 下载库中的bpmn
     * deploymentId 是  act_re_deployment 的id
     * @param deploymentId
     */
    @PostMapping("/viewPic")
    public void viewPic(String deploymentId)  {
        // 将生产的图片放到文件夹下
        // 获取图片资源名称
        List<String> list = processEngine.getRepositoryService()
                .getDeploymentResourceNames(deploymentId);

        // 定义图片资源名称
        String resourceName = list.get(0);
        if (list != null && list.size() > 0) {
            for (String name : list) {
                if (name.indexOf(".png") >= 0) {
                    resourceName = name;
                }
            }
        }

        // 获取图片的输入流
        InputStream in = processEngine.getRepositoryService()
                .getResourceAsStream(deploymentId, resourceName);

        File file = new File("C:\\Users\\WH2206003\\Desktop\\camunda\\"+resourceName);
        // 将输入流的图片写到D盘下
        try {
            FileUtils.copyInputStreamToFile(in, file);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

   @PostMapping("/getActivityStatistics")
    public CommonResult<Map> getActivityStatistics(String processDefinitionId){
        List<ActivityStatistics> activityStatistics = managementService
                .createActivityStatisticsQuery(processDefinitionId)
                .list();
        Map<String, Object> data = new HashMap<String, Object>();
        data.put("result", activityStatistics);

        return CommonResult.success(data);

    }


}
